/*
 * JJTEcmaScriptState.java - ScriptME
 * 
 * Copyright (c) 2009 Cesar Henriques <cesar at alttab.com.ar>.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Based on FESI Project
 * 
 * Contributors:
 * 	Jean-Marc Lugrin - initial API and implementation
 * 	Cesar Henriques <cesar at alttab.com.ar> - J2ME Porting and Extensions
 */
/*
 * 
 */

package org.scriptme.ecmascript.ast;

// TODO: Auto-generated Javadoc
/**
 * The Class JJTEcmaScriptState.
 */
public class JJTEcmaScriptState {

	/** The nodes. */
	private java.util.Stack nodes;

	/** The marks. */
	private java.util.Stack marks;

	/** The sp. */
	private int sp; // number of nodes on stack

	/** The mk. */
	private int mk; // current mark

	/** The node_created. */
	private boolean node_created;

	/**
	 * Instantiates a new jJT ecma script state.
	 */
	public JJTEcmaScriptState() {
		nodes = new java.util.Stack();
		marks = new java.util.Stack();
		sp = 0;
		mk = 0;
	}

	/*
	 * Determines whether the current node was actually closed and pushed. This
	 * should only be called in the final user action of a node scope.
	 */
	/**
	 * Node created.
	 * 
	 * @return true, if successful
	 */
	public boolean nodeCreated() {
		return node_created;
	}

	/*
	 * Call this to reinitialize the node stack. It is called automatically by
	 * the parser's ReInit() method.
	 */
	/**
	 * Reset.
	 */
	public void reset() {
		nodes.removeAllElements();
		marks.removeAllElements();
		sp = 0;
		mk = 0;
	}

	/*
	 * Returns the root node of the AST. It only makes sense to call this after
	 * a successful parse.
	 */
	/**
	 * Root node.
	 * 
	 * @return the node
	 */
	public Node rootNode() {
		return (Node) nodes.elementAt(0);
	}

	/* Pushes a node on to the stack. */
	/**
	 * Push node.
	 * 
	 * @param n
	 *            the n
	 */
	public void pushNode(Node n) {
		nodes.push(n);
		++sp;
	}

	/*
	 * Returns the node on the top of the stack, and remove it from the stack.
	 */
	/**
	 * Pop node.
	 * 
	 * @return the node
	 */
	public Node popNode() {
		if (--sp < mk) {
			mk = ((Integer) marks.pop()).intValue();
		}
		return (Node) nodes.pop();
	}

	/* Returns the node currently on the top of the stack. */
	/**
	 * Peek node.
	 * 
	 * @return the node
	 */
	public Node peekNode() {
		return (Node) nodes.peek();
	}

	/*
	 * Returns the number of children on the stack in the current node scope.
	 */
	/**
	 * Node arity.
	 * 
	 * @return the int
	 */
	public int nodeArity() {
		return sp - mk;
	}

	/**
	 * Clear node scope.
	 * 
	 * @param n
	 *            the n
	 */
	public void clearNodeScope(Node n) {
		while (sp > mk) {
			popNode();
		}
		mk = ((Integer) marks.pop()).intValue();
	}

	/**
	 * Open node scope.
	 * 
	 * @param n
	 *            the n
	 */
	public void openNodeScope(Node n) {
		marks.push(new Integer(mk));
		mk = sp;
		n.jjtOpen();
	}

	/*
	 * A definite node is constructed from a specified number of children. That
	 * number of nodes are popped from the stack and made the children of the
	 * definite node. Then the definite node is pushed on to the stack.
	 */
	/**
	 * Close node scope.
	 * 
	 * @param n
	 *            the n
	 * @param num
	 *            the num
	 */
	public void closeNodeScope(Node n, int num) {
		mk = ((Integer) marks.pop()).intValue();
		while (num-- > 0) {
			Node c = popNode();
			c.jjtSetParent(n);
			n.jjtAddChild(c, num);
		}
		n.jjtClose();
		pushNode(n);
		node_created = true;
	}

	/*
	 * A conditional node is constructed if its condition is true. All the nodes
	 * that have been pushed since the node was opened are made children of the
	 * the conditional node, which is then pushed on to the stack. If the
	 * condition is false the node is not constructed and they are left on the
	 * stack.
	 */
	/**
	 * Close node scope.
	 * 
	 * @param n
	 *            the n
	 * @param condition
	 *            the condition
	 */
	public void closeNodeScope(Node n, boolean condition) {
		if (condition) {
			int a = nodeArity();
			mk = ((Integer) marks.pop()).intValue();
			while (a-- > 0) {
				Node c = popNode();
				c.jjtSetParent(n);
				n.jjtAddChild(c, a);
			}
			n.jjtClose();
			pushNode(n);
			node_created = true;
		} else {
			mk = ((Integer) marks.pop()).intValue();
			node_created = false;
		}
	}
}
